﻿using System.Collections.Generic;
using System.Web.Mvc;
using ECommerce.Web.Commands;
using ECommerce.Web.Controllers;
using ECommerce.Web.Models;
using ECommerce.Web.ViewModels;
using ECommerce.Web.ViewQueries;
using Machine.Specifications;
using MvcContrib.TestHelper;
using Rhino.Mocks;

namespace Basket_controller_specs
{
    [Subject("Shopping basket")]
    public class When_a_shopper_views_their_basket : with_an_empty_basket
    {
        Because of = () =>
            {
                basketController.Index();
            };

        It should_return_view_of_basket = () =>
            {
                BasketView basketView = (BasketView) basketController.ViewData.Model;

                basketView.ShouldNotBeNull();
            };
    }

    [Subject("Shopping basket")]
    public class When_adding_a_product_to_the_basket : with_an_empty_basket
    {
        private static AddProductToBasketMessage addProductToBasketMessage;
        private static ActionResult result;

        Because of = () =>
            {
                addProductToBasketMessage = new AddProductToBasketMessage() {ProductId = 1, Quantity = 1};

                result = basketController.AddProduct(addProductToBasketMessage);
            };

        It should_add_product_to_basket = () =>
            {
                addProductToBasketCommand.AssertWasCalled(x => x.Handle(addProductToBasketMessage));
            };

        It should_redirect_to_basket_index = () =>
            {
                result.AssertActionRedirect().ToAction("Index");
            };
    }

    [Subject("Shopping basket")]
    public abstract class with_an_empty_basket
    {
        protected static IBasketViewQuery basketViewQuery;
        protected static IAddProductToBasketCommand addProductToBasketCommand;
        protected static IChangeProductQuantitiesInBasketCommand changeProductQuantitiesInBasketCommand;
        protected static IRemoveProductFromBasketCommand removeProductFromBasketCommand;
        protected static BasketController basketController;
        protected static Basket basket;

        Establish context = () =>
            {
                basket = new Basket();

                basketViewQuery = MockRepository.GenerateStub<IBasketViewQuery>();
                basketViewQuery.Stub(x => x.GetQuery()).Return(new BasketView());

                addProductToBasketCommand = MockRepository.GenerateStub<IAddProductToBasketCommand>();
                changeProductQuantitiesInBasketCommand = MockRepository.GenerateStub<IChangeProductQuantitiesInBasketCommand>();
                removeProductFromBasketCommand = MockRepository.GenerateStub<IRemoveProductFromBasketCommand>();

                basketController = new BasketController(basketViewQuery,
                                                        addProductToBasketCommand,
                                                        changeProductQuantitiesInBasketCommand,
                                                        removeProductFromBasketCommand);
            };
    }

    [Subject("Shopping basket")]
    public class When_updating_the_basket : With_an_item_in_a_basket
    {
        private static ChangeProductQuantitiesInBasketMessage message;
        private static ActionResult result;

        Because of = () =>
            {
                message = new ChangeProductQuantitiesInBasketMessage() {BasketId = 1};

                message.ProductQuantityMessages = new List<ChangeProductQuantitiesInBasketMessage.ProductQuantityMessage>()
                                                      {
                                                          new ChangeProductQuantitiesInBasketMessage.ProductQuantityMessage()
                                                              {
                                                                  ProductId = 1,
                                                                  Quantity = 1
                                                              }
                                                      };

                result = basketController.ChangeProductQuantities(message);
            };

        It should_update_basket_item_quantities = () =>
            {
                changeProductQuantitiesInBasketCommand.AssertWasCalled(x => x.Handle(message));
            };

        It should_redirect_to_basket_index = () =>
            {
                result.AssertActionRedirect().ToAction("Index");
            };
    }

    [Subject("Shopping basket")]
    public class When_removing_a_basket_item : With_an_item_in_a_basket
    {
        private static ActionResult result;

        Because of = () =>
            {
                result = basketController.RemoveProduct(1);
            };

        It should_remove_the_basket_item = () =>
            {
                removeProductFromBasketCommand.AssertWasCalled(x => x.Handle(1));
            };

        It should_redirect_to_basket_index = () =>
            {
                result.AssertActionRedirect().ToAction("Index");
            };
    }

    [Subject("Shopping basket")]
    public abstract class With_an_item_in_a_basket
    {
        protected static IBasketViewQuery basketViewQuery;
        protected static IAddProductToBasketCommand addProductToBasketCommand;
        protected static IChangeProductQuantitiesInBasketCommand changeProductQuantitiesInBasketCommand;
        protected static IRemoveProductFromBasketCommand removeProductFromBasketCommand;
        protected static BasketController basketController;
        protected static Basket basket;

        Establish context = () =>
            {
                basket = new Basket() {Id = 1};
                basket.AddBasketItem(new BasketItem() {Id = 1});

                basketViewQuery = MockRepository.GenerateStub<IBasketViewQuery>();

                addProductToBasketCommand = MockRepository.GenerateStub<IAddProductToBasketCommand>();
                changeProductQuantitiesInBasketCommand = MockRepository.GenerateStub<IChangeProductQuantitiesInBasketCommand>();
                removeProductFromBasketCommand = MockRepository.GenerateStub<IRemoveProductFromBasketCommand>();

                basketController = new BasketController(basketViewQuery,
                                                        addProductToBasketCommand,
                                                        changeProductQuantitiesInBasketCommand,
                                                        removeProductFromBasketCommand);
            };
    }
}
